package com.lippeng.taohua.db.connection;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Vector;

import com.lippeng.taohua.db.exception.TaoHuaDBException;

/**
 * Here,I maintain many connections in a Connection Pool.
 * 
 * Of course,it can provide connection and recover it
 * 
 * @author lippeng
 * 
 */
public class ConnectionPool {

	/**
	 * The Pool of connection,it need synchronized
	 */
	private Vector<Connection> connectionPool;

	/**
	 * The Single Object of this Class
	 */
	private static ConnectionPool self = new ConnectionPool();

	/**
	 * Private Constructor
	 */
	private ConnectionPool() {
		init();
	}

	/**
	 * Initialize the connection Pool . Default @param num = 10
	 * 
	 * @param num
	 */
	private void init() {
		// if no synchronized,I think it's all right.
		// But I add it for none reason,that's my choice
		synchronized (connectionPool) {
			connectionPool = new Vector<Connection>(
					ConnectionParam.minConnection);
			for (int i = 0; i < ConnectionParam.minConnection; i++) {
				connectionPool.add(createConnection());
			}
		}
	}

	/**
	 * Get the ConnectionPool
	 * 
	 * @return
	 */
	public static ConnectionPool getConnectionPool() {
		return self;
	}

	/**
	 * Get one Connection from Connection Pool
	 * 
	 * @return
	 * @throws
	 */
	public Connection getConnection() {
		synchronized (connectionPool) {
			Connection connection = null;
			if (connectionPool.size() > 0) {
				connection = connectionPool.firstElement();
				connectionPool.remove(0);
			} else {
				try {
					connectionPool.wait(ConnectionParam.waitTime);
					// There are 2 case :
					if (connectionPool.size() > 0) {
						// one case : it was notify by other thread
						// A single thread may hold a lock more than once
						connection = getConnection();
					} else {
						// the other case : the time was out
						// it is the current thread
						addConnections();
						connection = getConnection();
					}

				} catch (InterruptedException e) {
					e.printStackTrace();
					throw new TaoHuaDBException("Wait was interrupted");
				}
			}
			return connection;
		}
	}

	/**
	 * Pay back one Connection to Connection Pool
	 * 
	 * @param connection
	 * @return
	 */
	public void backConnection(Connection connection) {
		synchronized (connectionPool) {
			connectionPool.add(connection);

			if (1 == connectionPool.size()) {
				// Maybe someone is waiting
				connectionPool.notifyAll();
			}
		}
	}

	/**
	 * Create one Connection
	 * 
	 * @return
	 */
	private Connection createConnection() {
		Connection connection = null;
		try {
			connection = DriverManager.getConnection(ConnectionParam.url,
					ConnectionParam.user, ConnectionParam.password);
		} catch (Exception e) {
			e.printStackTrace();
			throw new TaoHuaDBException(
					"Create Connection Fail,Please Check the mysql-connector-java.jar exist and Build Path was added");
		}
		return connection;
	}

	/**
	 * Do this when there is no connection for wait time millisecond
	 */
	private void addConnections() {
		synchronized (connectionPool) {
			for (int i = 0; i < ConnectionParam.addSize; i++) {
				connectionPool.add(createConnection());
			}
		}
	}

}
